package com.yfyszk.kingbird.upload;

import com.yfyszk.kingbird.common.constants.CommonFileConstant;
import com.yfyszk.kingbird.common.utils.DateUtils;
import com.yfyszk.kingbird.common.utils.IdWorkerUtils;
import com.yfyszk.kingbird.common.utils.PlatformUtils;
import com.yfyszk.kingbird.common.vo.UploadFileVO;
import com.yfyszk.kingbird.exception.GlobalServiceException;
import io.minio.*;
import io.minio.errors.ErrorResponseException;
import io.minio.http.Method;
import lombok.extern.slf4j.Slf4j;
import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;

/**
 * @ClassName MinioService
 * @Description: TODO
 * @Author wgc
 * @Date 2020/12/10 13:56
 * @Version V1.0
 **/
@Slf4j
@Service
public class MinioService {

    /**
     * minio参数
     */
    @Value("${miniourl}")
    private String ENDPOINT;
    @Value("${minioaccesskey}")
    private String ACCESS_KEY;
    @Value("${miniosecretkey}")
    private String SECRET_KEY;

    /**
     * 默认大小 50M
     */
    public static final long DEFAULT_MAX_SIZE = 500 * 1024 * 1024;

    /**
     * 桶占位符
     */
    private static final String BUCKET_PARAM = "${bucket}";
    /**
     * bucket权限-只读
     */
    private static final String READ_ONLY = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetObject\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";
    /**
     * bucket权限-只读
     */
    private static final String WRITE_ONLY = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:AbortMultipartUpload\",\"s3:DeleteObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";
    /**
     * bucket权限-读写
     */
    private static final String READ_WRITE = "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:GetBucketLocation\",\"s3:ListBucket\",\"s3:ListBucketMultipartUploads\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "\"]},{\"Effect\":\"Allow\",\"Principal\":{\"AWS\":[\"*\"]},\"Action\":[\"s3:DeleteObject\",\"s3:GetObject\",\"s3:ListMultipartUploadParts\",\"s3:PutObject\",\"s3:AbortMultipartUpload\"],\"Resource\":[\"arn:aws:s3:::" + BUCKET_PARAM + "/*\"]}]}";

    /**
     * 文件url前半段
     *
     * @param bucket 桶
     * @return 前半段
     */
    public String getObjectPrefixUrl(String bucket) {
        return String.format("%s/%s/", ENDPOINT, bucket);
    }

    /**
     * 创建桶
     *
     * @param bucket 桶
     */
    public void makeBucket(String bucket) throws Exception {
        log.info("ENDPOINT：{}", ENDPOINT);
        log.info("ACCESS_KEY：{}", ACCESS_KEY);
        log.info("SECRET_KEY：{}", SECRET_KEY);
        MinioClient client = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
        // 判断桶是否存在
        boolean isExist = client.bucketExists(BucketExistsArgs.builder().bucket(bucket).build());
        if (!isExist) {
            // 新建桶
            client.makeBucket(MakeBucketArgs.builder().bucket(bucket).build());
        }
    }

    /**
     * 更新桶权限策略
     *
     * @param bucket 桶
     * @param policy 权限
     */
    public void setBucketPolicy(String bucket, String policy) throws Exception {
        log.info("ENDPOINT：{}", ENDPOINT);
        log.info("ACCESS_KEY：{}", ACCESS_KEY);
        log.info("SECRET_KEY：{}", SECRET_KEY);
        MinioClient client = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
        switch (policy) {
            case "read-only":
                client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).config(READ_ONLY.replace(BUCKET_PARAM, bucket)).build());
                break;
            case "write-only":
                client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).config(WRITE_ONLY.replace(BUCKET_PARAM, bucket)).build());
                break;
            case "read-write":
                client.setBucketPolicy(SetBucketPolicyArgs.builder().bucket(bucket).config(READ_WRITE.replace(BUCKET_PARAM, bucket)).build());
                break;
            case "none":
            default:
                break;
        }
    }

    /**
     * 上传本地文件
     *
     * @param bucket    桶
     * @param objectKey 文件key
     * @param filePath  文件路径
     * @return 文件url
     */
    public String uploadFile(String bucket, String objectKey, String filePath) throws Exception {
        MinioClient client = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
        client.uploadObject(UploadObjectArgs.builder().bucket(bucket).object(objectKey).filename(filePath).build());
        return getObjectPrefixUrl(bucket) + objectKey;
    }

    /**
     * 流式上传文件
     *
     * @param bucket      桶
     * @param objectKey   文件key
     * @param inputStream 文件输入流
     * @return 文件url
     */
    public String uploadInputStream(String bucket, String objectKey, InputStream inputStream, String contentType) throws Exception {
      /*  MinioClient client = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
        client.putObject(PutObjectArgs.builder().bucket(bucket).object(objectKey).stream(inputStream, inputStream.available(), -1).contentType(contentType).build());
     */
        MinioClient client = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
        client.putObject(PutObjectArgs.builder().bucket(bucket).object(objectKey).stream(inputStream, inputStream.available(), -1).contentType("image/png").contentType("image/jpeg").build());
        return getObjectPrefixUrl(bucket) + objectKey;
    }

    /**
     * 生成缩略图和原图
     *
     * @param bucket
     * @param objectKey
     * @param inputStream
     * @return java.lang.String
     * @author wgc
     * @date 2020/12/4 0004 10:33
     */
    public String uploadInputStreamForThumb(String bucket, String objectKey, InputStream inputStream, String contentType) throws Exception {
        log.info("ENDPOINT：{}", ENDPOINT);
        log.info("ACCESS_KEY：{}", ACCESS_KEY);
        log.info("SECRET_KEY：{}", SECRET_KEY);
        MinioClient client = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
        client.putObject(PutObjectArgs.builder().bucket(bucket).object(objectKey).stream(inputStream, inputStream.available(), -1).contentType("image/png").build());
        String fileName = "1.png";
        String newName = IdWorkerUtils.getInstance().nextId() + "";
        String objectNameThumb = newName + ".png";
        String tmpPath = "D:\\code";
        String id = IdWorkerUtils.getInstance().nextId() + "";
        File newFile = new File(tmpPath + File.separator + newName + ".png");

        Thumbnails.of("D:\\1.png").forceSize(100, 100).toFile(newFile);
        FileInputStream inputStreamThumb = new FileInputStream(newFile);

        System.out.println(objectNameThumb + "-----");
        client.putObject(PutObjectArgs.builder().bucket(bucket).object(objectNameThumb).stream(inputStreamThumb, inputStreamThumb.available(), -1).contentType("image/png").build());

        return getObjectPrefixUrl(bucket) + objectKey;
    }


    /**
     * 生成缩略图和原图
     *
     * @param bucket
     * @param objectKey
     * @return java.lang.String
     * @author wgc
     * @date 2020/12/4 0004 10:33
     */
    public UploadFileVO uploadInputStreamForThumbForWebOrApp(String bucket, String objectKey, HttpServletRequest request) {
        log.info("ENDPOINT：{}", ENDPOINT);
        log.info("ACCESS_KEY：{}", ACCESS_KEY);
        log.info("SECRET_KEY：{}", SECRET_KEY);
        UploadFileVO file = null;
        try {
            MultipartHttpServletRequest multiRequest = (MultipartHttpServletRequest) request;
            CommonsMultipartResolver multipartResolver = new CommonsMultipartResolver(
                    multiRequest.getSession().getServletContext());
            String fileName = "";// 文件名称
            if (multipartResolver.isMultipart(multiRequest)) {
                Iterator<String> iter = multiRequest.getFileNames();
                while (iter.hasNext()) {
                    List<MultipartFile> multipartFiles = multiRequest.getFiles(iter.next());
                    if (multipartFiles != null && !multipartFiles.isEmpty()) {
                        for (final MultipartFile multipartFile : multipartFiles) {
                            long size = multipartFile.getSize();
                            if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE)
                            {
                                throw new GlobalServiceException(1,"已超出文件大小");
                            }
                            file = new UploadFileVO();
                            fileName = multipartFile.getOriginalFilename();// 获取上传的文件名字
                            file.setFileName(fileName);
                            file.setFileSize(String.valueOf(multipartFile.getSize()));
                            String suffixName = multipartFile.getOriginalFilename()
                                    .substring(multipartFile.getOriginalFilename().lastIndexOf(".") + 1);
                            file.setSuffixName(suffixName);
                            objectKey = objectKey + "."+suffixName;
                            log.info("原文件:{}" + objectKey);
                            String contentType = multipartFile.getContentType();
                            InputStream inputStream = multipartFile.getInputStream();
                            MinioClient client = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
                            client.putObject(PutObjectArgs.builder().bucket(bucket).object(objectKey).stream(inputStream, inputStream.available(), -1).contentType(contentType).build());
                            file.setProjectFileUrl(bucket + "/" + objectKey);
                            log.info("原文件上传成功");
                            if (checkFileType(suffixName)) {
                                String newName = IdWorkerUtils.getInstance().nextId() + "";
                                String objectNameThumb = newName + "."+suffixName;
                                String tmpPath = null;
                                if (PlatformUtils.isWindows()) {
                                    tmpPath = CommonFileConstant.WINDOWS_FILE_URL;
                                } else if (PlatformUtils.isLinux()) {
                                    tmpPath = CommonFileConstant.LINUX_BACK_FILE_URL;

                                }
                                File newFile = new File(tmpPath + File.separator + newName + "."+suffixName);
                                InputStream inputStream_ = multipartFile.getInputStream();
                                Thumbnails.of(inputStream_).forceSize(100, 100).toFile(newFile);
                                FileInputStream inputStreamThumb = new FileInputStream(newFile);
                                log.info("缩略图文件:{}" + objectNameThumb);
                                client.putObject(PutObjectArgs.builder().bucket(bucket).object(objectNameThumb).stream(inputStreamThumb, inputStreamThumb.available(), -1).contentType(contentType).build());
                                file.setThumbnailUrl(bucket + "/" + objectNameThumb);
                                newFile.delete();
                                inputStream_.close();
                            }
                            inputStream.close();
                            log.info("返回的文件:{}", file);
                            return file;
                        }

                    }

                }

            }
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return file;
        }
    }

    /**
     * 下载文件
     *
     * @param bucket    桶
     * @param objectKey 文件key
     * @return 文件流
     */
    public InputStream download(String bucket, String objectKey) throws Exception {
        MinioClient client = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
        return client.getObject(GetObjectArgs.builder().bucket(bucket).object(objectKey).build());
    }

    public void downloadFile(String bucketName, String fileName, String originalName, HttpServletResponse response) {
        try {
            MinioClient client = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();

            InputStream file = client.getObject(bucketName, fileName);
            String filename = new String(fileName.getBytes("ISO8859-1"), StandardCharsets.UTF_8);
            if (StringUtils.isNotEmpty(originalName)) {
                fileName = originalName;
            }
            response.setHeader("Content-Disposition", "attachment;filename=" + filename);
            ServletOutputStream servletOutputStream = response.getOutputStream();
            int len;
            byte[] buffer = new byte[1024];
            while ((len = file.read(buffer)) > 0) {
                servletOutputStream.write(buffer, 0, len);
            }
            servletOutputStream.flush();
            file.close();
            servletOutputStream.close();
        } catch (ErrorResponseException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 文件复制
     *
     * @param sourceBucket    源桶
     * @param sourceObjectKey 源文件key
     * @param bucket          桶
     * @param objectKey       文件key
     * @return 新文件url
     */
    public String copyFile(String sourceBucket, String sourceObjectKey, String bucket, String objectKey) throws Exception {
        MinioClient client = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
        CopySource source = CopySource.builder().bucket(sourceBucket).object(sourceObjectKey).build();
        client.copyObject(CopyObjectArgs.builder().bucket(bucket).object(objectKey).source(source).build());
        return getObjectPrefixUrl(bucket) + objectKey;
    }

    /**
     * 删除文件
     *
     * @param bucket    桶
     * @param objectKey 文件key
     */
    public void deleteFile(String bucket, String objectKey) throws Exception {
        MinioClient client = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
        client.removeObject(RemoveObjectArgs.builder().bucket(bucket).object(objectKey).build());
    }

    /**
     * 获取文件签名url
     *
     * @param bucket    桶
     * @param objectKey 文件key
     * @param expires   签名有效时间  单位秒
     * @return 文件签名地址
     */
    public String getSignedUrl(String bucket, String objectKey, int expires) throws Exception {
        MinioClient client = MinioClient.builder().endpoint(ENDPOINT).credentials(ACCESS_KEY, SECRET_KEY).build();
        return client.getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucket).object(objectKey).expiry(expires).build());
    }

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");

    public static void main(String[] args) {
        String bucket = DateUtils.nowDayTimeStamp();
        String id = IdWorkerUtils.getInstance().nextId() + "";

        // String  filePath = "/" + DateUtils.nowDayTimeStamp() + "/" + id;
        String objectKey = id + ".png";
        try {

            // 创建桶
            //makeBucket(bucket);
            // 设置桶读写权限
            //setBucketPolicy(bucket, "read-write");

            // 上传本地文件
            //String url1 = uploadFile(bucket, objectKey, "d:\\1.png");
            // 输出  http://127.0.0.1:9000/demo/123.png
            //System.out.println(bucket+"/"+objectKey);
            // System.out.println(url1);
            // 上传文件流
            // String objectKeyInputStream = IdWorkerUtils.getInstance().nextId() + ".jpg";
            //String url2 = uploadInputStreamForThumb(bucket, objectKeyInputStream, new FileInputStream(new File("D://5.jpg")), null);
            // 输出  http://127.0.0.1:9000/demo/123.png
            //System.out.println(url2);
            // 下载文件
            //InputStream inputStream = download(bucket, objectKey);
            // 文件复制
            //String url3 = copyFile(bucket, objectKey, "test", "test/abc.png");
            // 输出  http://127.0.0.1:9000/test/abc.png
            //System.out.println(url3);
            // 删除文件
            //deleteFile("test", "test/abc.png");
            // 获取文件签名url
            //String sign = getSignedUrl(bucket, objectKey, 600);
            // 该路径可访问文件五分钟
            //System.out.println(sign);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    private static String[] allowFiles = {"bmp", "jpg", "png", "tif", "gif", "pcx", "tga", "exif", "fpx"};

    public static boolean checkFileType(String suffixName) {
        Iterator<String> type = Arrays.asList(allowFiles).iterator();
        while (type.hasNext()) {
            String ext = type.next();
            if (suffixName.toLowerCase().equals(ext)) {
                return true;
            }
        }
        return false;
    }
}